package core

import (
	options "PcapCapture/src/options"
	"encoding/json"
	"fmt"
	"log"
	"net"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"
)

type InfoSaver struct {
	message <-chan PacketInfo
	ipOpt   options.IpInfoLogOpt
}

func NewInfoSaver(message <-chan PacketInfo, wg *sync.WaitGroup, opt options.IpInfoLogOpt) *InfoSaver {
	req := &InfoSaver{message: message, ipOpt: opt}
	req.SaverRun(wg)
	return req
}

func (saver *InfoSaver) saveToFile(fileName string, dataSource any) error {
	// 1. 序列化为JSON
	data, err := json.Marshal(dataSource)
	if err != nil {
		return fmt.Errorf("JSON序列化失败: %w", err)
	}
	data = append(data, '\n') // 添加换行符作为分隔

	// 获得路径
	root, _ := getProjectRoot()
	var (
		outputPath        string
		currentTime       time.Time
		outputPathOnlyDir string
	)

	currentTime = time.Now()
	//fmt.Println(outputPathOnlyDir)

	//这里采用泛型，根据不同的数据类型改变保存的路径
	switch dataSource.(type) {

	case PacketInfo:
		outputPathOnlyDir = filepath.Join(root, "Output", fileName)
		outputPath = filepath.Join(outputPathOnlyDir, fmt.Sprintf("%s.json", currentTime.Format("2006-01-02")))
	case *StatsInfo:
		outputPathOnlyDir = filepath.Join(root, "Output", "ip", fileName)
		outputPath = filepath.Join(outputPathOnlyDir, fmt.Sprintf("%s_Stats.json", currentTime.Format("2006-01-02")))
		//fmt.Println(outputPath)
	}

	// 创建文件夹
	err = createNotExistDir(outputPathOnlyDir)
	if err != nil {
		fmt.Printf("%s 文件夹创建失败\n", outputPathOnlyDir)
		return fmt.Errorf("创建文件夹失败: %w", err)
	}
	//fmt.Printf("outputPath:%s\n", outputPath)

	// 2. 打开文件（追加模式）
	file, err := os.OpenFile(outputPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		return fmt.Errorf("打开文件失败: %w", err)
	}

	defer func() {
		if err := safeClose(file); err != nil {
			log.Printf("警告: %v", err)
		}
	}()

	// 3. 写入数据
	if _, err := file.Write(data); err != nil {
		return fmt.Errorf("写入文件失败: %w", err)
	}

	return nil
}

func safeClose(file *os.File) error {
	if err := file.Close(); err != nil {
		return fmt.Errorf("文件关闭失败: %w", err)
	}
	return nil
}

// 获取项目根目录（假设main.go在项目根目录）
func getProjectRoot() (string, error) {
	// 方案1：通过执行文件路径推导（适用于部署环境）
	exe, err := os.Executable()
	if err != nil {
		return "", err
	}
	return filepath.Dir(exe), nil

	// 方案2：通过工作目录推导（适用于开发环境）
	// return os.Getwd()
}

// 检测文件夹是否存在并自动创建不存在的文件夹
func createNotExistDir(dir string) error {
	if _, err := os.Stat(dir); os.IsNotExist(err) {
		if err := os.MkdirAll(dir, 0755); err != nil {
			return err
		}
	}
	return nil
}

// SaverRun 作为门面，启动Saver
func (saver *InfoSaver) SaverRun(wg *sync.WaitGroup) {
	defer wg.Done()
	Stats := make(map[string]*StatsInfo)
	// 在SaverRun 结束时，保存所有的Key
	defer func() {
		for key, data := range Stats {
			_ = saver.saveToFile(key, data)
		}
	}()
	for {
		select {
		// 从消息队列接收到 PacketInfo 的统计信息后，汇总并保存在map中
		case data, ok := <-saver.message:
			if !ok {
				log.Println("消息channel已关闭，停止运行")
				return
			}

			ip := data.SrcIP
			if ip != "" {
				info, exists := Stats[ip]
				if !exists {
					info = new(StatsInfo)
					Stats[ip] = info
				}
				info.PacketSum++
				info.Length += float64(data.Metadata.Length) / 1024
				Stats[ip] = info

				mylog := saver.getLogStr(data, saver.ipOpt)

				if mylog != "" {
					log.Println(mylog)
				}
				_ = saver.saveToFile(data.DeviceName, data)
			}

		default:
			continue
		}
	}

}

func (saver *InfoSaver) getLogStr(info PacketInfo, ipOpt options.IpInfoLogOpt) string {
	var builder strings.Builder

	// 辅助函数处理单个IPInfo
	addIPInfo := func(prefix string, ipInfo *IpInfo, info *PacketInfo) {
		if ipInfo == nil {
			return
		}
		builder.WriteString(prefix)
		if prefix == "Src: " {
			builder.WriteString(fmt.Sprintf("Ip=%s ", info.SrcIP))
		} else {
			builder.WriteString(fmt.Sprintf("Ip=%s ", info.DstIP))
		}

		if ipOpt.CountryName && ipInfo.CountryName != "" {
			builder.WriteString(fmt.Sprintf("Country=%s ", ipInfo.CountryName))
		}
		if ipOpt.RegionName && ipInfo.RegionName != "" {
			builder.WriteString(fmt.Sprintf("Region=%s ", ipInfo.RegionName))
		}
		if ipOpt.CityName && ipInfo.CityName != "" {
			builder.WriteString(fmt.Sprintf("City=%s ", ipInfo.CityName))
		}
		if ipOpt.DistrictName && ipInfo.DistrictName != "" {
			builder.WriteString(fmt.Sprintf("District=%s ", ipInfo.DistrictName))
		}
		if ipOpt.OwnerDomain && ipInfo.OwnerDomain != "" {
			builder.WriteString(fmt.Sprintf("Owner=%s ", ipInfo.OwnerDomain))
		}
		if ipOpt.IspDomain && ipInfo.IspDomain != "" {
			builder.WriteString(fmt.Sprintf("ISP=%s ", ipInfo.IspDomain))
		}
		if ipOpt.CountryCode && ipInfo.CountryCode != "" {
			builder.WriteString(fmt.Sprintf("CountryCode=%s ", ipInfo.CountryCode))
		}
		if ipOpt.ContinentCode && ipInfo.ContinentCode != "" {
			builder.WriteString(fmt.Sprintf("Continent=%s ", ipInfo.ContinentCode))
		}
	}

	// 处理源和目的IP
	builder.WriteString(info.ProcessName + " ")
	builder.WriteString(" -> ")
	if info.Host != "" {
		builder.WriteString(info.Host)
	} else {
		addIPInfo("Dst: ", &info.DstIPinfo, &info)
	}
	builder.WriteString("\n")

	builder.WriteString(fmt.Sprintf("Length: %d\n", info.Metadata.Length))
	builder.WriteString("--------\n")

	if (info.ProcessName == "" && info.Host == "") || net.ParseIP(info.DstIP).IsPrivate() || net.ParseIP(info.DstIP).IsLoopback() || net.ParseIP(info.DstIP).IsLinkLocalMulticast() {
		return ""
	}

	return strings.TrimSpace(builder.String())
}
